package main

import (
	"errhanding/filelistlngserver/filelisting"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

// 声明一个函数类型
// 这样是声明的函数只是一个占位用
type appHandel func(writer http.ResponseWriter, request *http.Request) error


// 函数式编程
func errWrapper (handel appHandel) func(writer http.ResponseWriter, request *http.Request)  {

	// 函数式编程，必须return 函数类型, 因为我的返回值就是函数
	return func(writer http.ResponseWriter, request *http.Request) {

		// 捕获异常
		defer func() {
			if r := recover(); r != nil {
				log.Panicf("Panic: %v", r)
				http.Error(writer, http.StatusText(http.StatusInternalServerError),
					http.StatusInternalServerError)
			}

		}()


		err := handel(writer, request)
		if err != nil {

			// 如果是我们自己异常，就展示给用户看
			if userError, ok := err.(UserError); ok {
				http.Error(writer, userError.Message(), http.StatusBadRequest)
				return
			}

			code := http.StatusOK
			switch {
			case os.IsNotExist(err): // 如果是文件不存在类型
				// 如果是文件不存在
				// 给出403 响应
				code = http.StatusForbidden
			default:
				code = http.StatusInternalServerError
			}

			http.Error(writer, "文件不存在", code)
		}
	}
}

// 自定义异常
// 定义一个 UserError 接口
type UserError interface {
	error
	Message() string
}

// 方式一
// 这是写在一起的样子，并不美观，因为 err 信息会报错到控制台
// 下面会有一个比较优雅点例子
func serverTest()  {
	http.HandleFunc("/list/",
		func(writer http.ResponseWriter, request *http.Request) {

			// 获取路径
			// 获取 request.URL.Path 这个全路径，但是要把请求 "/list/" 去掉，才能拿到文件路径
			// 相当于就是 request.URL.Path 进行了切片，从 "/list/" 位置开始截取
			path := request.URL.Path[len("/list/"):]
			// 打开文件流
			file, err := os.Open(path)
			if err != nil {
				// panic(err)

				// 设置响应错误信息，状态为 500
				http.Error(writer, err.Error(),http.StatusInternalServerError)

				// 表示不继续往下执行
				return
			}

			defer file.Close()

			// 读取文件里面所有的信息
			all, err := ioutil.ReadAll(file)
			if err != nil {
				panic(err)
			}

			// 写入响应流
			writer.Write(all)

		})

	// 开启服务器
	err := http.ListenAndServe(":8888", nil)
	if err != nil {
		panic(err)
	}
}


func main() {

	http.HandleFunc("/list/",

		// 包装一层，因为 AppHandelFileList 有返回值
		errWrapper(filelisting.AppHandelFileList))

	// 开启服务器
	err := http.ListenAndServe(":8888", nil)
	if err != nil {
		panic(err)
	}

}
